JWT(Json Web Token)
✒️ 2025-05-16 09:07 내용 수정
두 시스템 간의 정보를 안전하게 주고받기 위해 JSON 형식으로 인코딩 된 형식
- 공식 문서 : https://jwt.io/introduction
- 아래 내용은 공식 문서를 보고 번역 및 정리하면서 개인적으로 필요한 부분을 보충하였다.
- JWT에 인코딩된 정보는 디지털로 서명되어 있어 검증되고 안전하다.
- HMAC과 같은 알고리즘으로 비밀 서명을 하거나 RSA나 ECDSA와 같은 public/private key 쌍으로 서명할 수 있다.
- 서명된 토큰은 그 안에 포함된 클레임의 무결성을 검증할 수 있으며, 암호화된 토큰은 그 클레임(Claims)들을 다른 주체로부터 숨길 수 있다.
- 원문의 party를 chatGPT를 통해 주체로 번역했으며, 토큰을 주고 받거나 서명하는 각 시스템이나 개인을 뜻한다.
- 서버와 클라이언트가 JWT를 주고 받으면 각각이 party가 된다.
- 토큰이 public/private key 쌍으로 서명되어 있다면, 이 서명은 private key를 소유한 주체만이 서명 했음을 인증해준다.
JWT를 사용하는 경우
- Authorization(인가) : 사용자가 로그인하면 각각의 다음 요청은 JWT를 포함하여 사용자가 토큰으로 허용된 라우트, 서비스, 자원에 접근할 수 있다.
- Single Sign On은 요즘 JWT를 널리 사용하는 기능으로, 작은 오버헤드와 서로 다른 도메인 간에 쉽게 사용할 수 있다.
- 정보 교환 : JWT는 주체 간의 정보를 안전하게 교환할 수 있는 방법이다.
- JWT는 public/private key 쌍과 같이 서명될 수 있기 때문에 정보를 보낸 주체가 누구인지 확신할 수 있다.
- 추가적으로 서명은 헤더와 payload를 사용하여 계산되기 때문에 컨텐츠가 변조되지 않았음을 확인할 수 있다.
구조
- JWT는 3개의 점(
.)으로 구분되는Header,Payload,Signature로 이루어져 있다. - 이 형식은 HTML과 HTTP 환경에서 쉽게 전달이 가능하고, SAML과 같이 XML에 기반을 둔 스탠다드와 비교하여 더 간결하다.
# Header.Payload.Signature
xxxxxx.yyyyyy.zzzzzz

1. Header
- 토큰의 타입(JWT)와 서명에 사용된 알고리즘(HMAC SHA236, RSA) 정보가 담겨 있다.
{
"alg": "HS256", // 서명에 사용된 알고리즘
"typ": "JWT" // 토큰 타입
}
2. Payload
- 클레임을 포함하는 영역이다.
- 클레임은 entity(보통은 사용자)와 추가적인 데이터에 대한 정보이다.
- 클레임에는 3가지 타입이 있다.
-
Registered claims(표준 클레임) : 유용하고 상호 운용 가능한 클레임을 제공하기 위해 사전 정의된 클레임들의 모음으로, 필수는 아니지만 권장된다.
- iss(issuer), exp(expiration time), sub(subject), aud(audience) 등이 있다.
- JWT는 간결해야 하기에 클레임 이름은 3글자로만 되어 있다.
-
Public claims(공개 클레임) : JWT를 사용하는 사람들이 정의할 수 있는 클레임이다.
- 충돌을 피하기 위해 IANA JSON Web Token Registry나 충돌을 방지할 수 있는 네임 스페이스를 포함하는 URI로 정의해야 한다.
-
Private claims(비공개 클레임) : 클레임 사용을 동의한 주체 간의 정보를 공유하기 위해 생성된 커스텀 클레임으로, 이 클레임은 표준 클레임도 공개 클레임도 아니다.
{
"sub": "1234567890", // subject
"name": "John Doe", // 이름
"iat": 1516239022 // issued at
}
3. Signature
- signature 부분을 생성하려면 암호화된 header, 암호화된 payload, 시크릿, header안에 알고리즘 정보, 그리고 서명이 필요하다.
- signature는 메시지가 전송되는 동안 변경되지 않았음을 검증하고, private key로 서명된 토큰의 경우엔 JWT를 전송한 대상이 누구인지 검증할 수 있다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
)
JWT 사용 시 주의 사항
- Authentication(인증)에서 사용자가 credentials(자격 증명)을 사용하여 성공적으로 로그인하면 JWT가 반환 된다.
- 이 토큰은 credential(자격 증명)이므로, 보안 문제를 방지하기 위해 큰 주의를 기울여야 하며, 일반적으로 토큰을 필요 이상으로 보관하지 않는 것이 좋다.
- 기한이 지난 토큰을 가지고 있으면 보안 상 문제가 커질 수 있어 토큰의 수명을 제한하는 것이 좋다.
- 또한 브라우저 저장소는 보안이 취약하기에 민감한 session 데이터를 브라우저 저장소에 저장하지 말아야 한다.
- 애플리케이션에 필요한 인증은 데이터가 저장된 장치의 로컬 권한을 통해 사용자가 우회할 수 있어 민감한 정보를 로컬 저장소에 저장하는 것은 피해야 한다.
- 브라우저 보안 보장으로 인해 데이터에 접근하는 것이 인증이나 인가가 아닌 경우에 로컬 저장소를 사용하는 것이 적절하다.
- 참고 자료 : HTML5 Security Local Storage
- 사용자가 보호된 라우트나 자원에 접근하고자 할 때 사용자 에이전트는 Authorization header에
Bearer schema를 사용하여 JWT를 전송해야 한다.
Authorization: Bearer <token>
-
HTTP header를 사용하여 JWT를 전송하면 JWT가 너무 커지지 않도록 조심해야 한다.
- 일부 서버는 header에 8 KB을 받지 못한다.
- JWT에 너무 많은 정보를 넣는 대신에 Auth0 Fine-Grained Authorization과 같은 방법으로 대체하는 것이 좋다.
-
토큰이 Authorization header에 담겨 보내질 경우, Cross-Origin Resource Sharing(CORS)은 쿠키를 사용하지 않는 한 문제를 일으키지 않는다.
-
서명된 토큰을 사용할 경우 토큰에 있는 정보는 다른 사용자나 주체에게 노출될 수 있으며, 다른 사용자나 주체는 이 정보를 변경할 수 없다.
- 따라서 비밀 정보는 토큰 안에 포함되어선 안된다.
JWT 획득 및 자원 접근 과정
- 애플리케이션이나 클라이언트가 Authorization 서버에 (Authorization)인가를 요청한다.
- Authorization(인가)가 허가되면 Authorization 서버에선 애플리케이션/클라이언트로 자원 서버에 접근할 수 있는 접근 토큰을 전송한다.
- 애플리케이션/클라이언트가 접근 토큰을 사용하여 자원 서버에 API와 같은 보호된 자원에 접근한다.
- 이미지는 공식 문서의 이미지에 설명을 추가하여 그렸다.
